//
// GPSMapEdit
// (c) Konstantin Galichsky (kg@geopainting.com), 2002-2007
// (c) Nikita Karnauhov (jinx@navitel.su), 2007
//
// Copy the selection to the clipboard.
//

# include "StdAfx.h"
# include "Copy.h"
# include "Types.h"
# include "Clipboard.h"
# include "Selection.h"
# include "Globals.h"

template <typename T> inline
void AddData (BYTE * _pData, size_t & _cOffset, T _SrcData, size_t _cDataSize) {
//	assert (_cDataSize >= sizeof (T));
	* reinterpret_cast <T *> (_pData + _cOffset) = _SrcData;
	_cOffset += _cDataSize;
}

void AddData (BYTE * _pData, size_t & _cOffset, const string_t & _SrcData) {
	const size_t cLen = _SrcData.size ();

	* reinterpret_cast <size_t *> (_pData + _cOffset) = cLen;
	_cOffset += sizeof (size_t);

	::memcpy (_pData + _cOffset, _SrcData.data (), cLen*sizeof (char));
	_cOffset += cLen*sizeof (char);
}

static
void _PrepareElement (const rgn_element_t & _element, bool _bPolyline, size_t & _cBytes) {
	if (_element.bDeleted)
		return;

	_cBytes += sizeof (BYTE);    // cLevel
	_cBytes += sizeof (BYTE);    // bHole

	_cBytes += sizeof (size_t);  // cPoints
	_cBytes += sizeof (point_t)*_element.points.size ();

	if (_bPolyline) {
		_cBytes += sizeof (size_t);  // cPointExtras
		if (_element.pExtra) {
			const point_extras_t & PointExtras = _element.pExtra->PointExtras;
			const size_t cPointExtras = PointExtras.size ();
			for (size_t cPE = 0; cPE < cPointExtras; ++ cPE) {
				const rgnode_t * const pNode = PointExtras [cPE].GetRGNode ();
				if (pNode != NULL)
					pNode->pExtra = reinterpret_cast<void *> (true);

				const numbers_t & Numbers = PointExtras [cPE].Numbers;
				if (Numbers.pCityLeftAfter)
					Numbers.pCityLeftAfter->bMarked = true;
				if (Numbers.pCityRightAfter)
					Numbers.pCityRightAfter->bMarked = true;
				if (Numbers.pZipLeftAfter)
					Numbers.pZipLeftAfter->bMarked = true;
				if (Numbers.pZipRightAfter)
					Numbers.pZipRightAfter->bMarked = true;
			}

			_cBytes += sizeof (size_t)*cPointExtras; // Node ID
			_cBytes += sizeof (bool)  *cPointExtras; // bHasNumbers
			_cBytes += sizeof (BYTE)  *cPointExtras; // wLeftParity
			_cBytes += sizeof (WORD)  *cPointExtras; // wLeftFrom
			_cBytes += sizeof (WORD)  *cPointExtras; // wLeftTo
			_cBytes += sizeof (BYTE)  *cPointExtras; // wRightParity
			_cBytes += sizeof (WORD)  *cPointExtras; // wRightFrom
			_cBytes += sizeof (WORD)  *cPointExtras; // wRightTo
			_cBytes += sizeof (size_t)*cPointExtras; // Zip Left
			_cBytes += sizeof (size_t)*cPointExtras; // Zip Right
			_cBytes += sizeof (size_t)*cPointExtras; // City Left
			_cBytes += sizeof (size_t)*cPointExtras; // City Right
		}
	}
}

static
void _SaveElement (const rgn_element_t & _element, bool _bPolyline, BYTE * _pData, size_t & _cOffset) {
	AddData (_pData, _cOffset, _element.cLevel, sizeof (BYTE));
	AddData (_pData, _cOffset, _element.bHole,  sizeof (BYTE));

	// Save points.
	const points_t & points = _element.points;
	const size_t cPoints = points.size ();
	AddData (_pData, _cOffset, cPoints, sizeof (size_t));
	for (size_t cPoint = 0; cPoint < cPoints; ++ cPoint)
		AddData (_pData, _cOffset, points [cPoint], sizeof (point_t));

	// Save point extras.
	if (_bPolyline) {
		if (_element.pExtra) {
			const point_extras_t & PointExtras = _element.pExtra->PointExtras;
			const size_t cPointExtras = PointExtras.size ();
			AddData (_pData, _cOffset, cPointExtras, sizeof (size_t));

			for (size_t cPoint = 0; cPoint < cPointExtras; ++ cPoint) {
				const rgnode_t * const pRGNode = PointExtras [cPoint].GetRGNode ();
				AddData (_pData, _cOffset, pRGNode == NULL ? -1 : reinterpret_cast<DWORD> (pRGNode->pExtra) - 1, sizeof (size_t));

				const numbers_t & Numbers = PointExtras [cPoint].Numbers;
				AddData (_pData, _cOffset, Numbers.bHasNumbers,  sizeof (bool));
				AddData (_pData, _cOffset, Numbers.wLeftParity,  sizeof (BYTE));
				AddData (_pData, _cOffset, Numbers.wLeftBefore,  sizeof (WORD));
				AddData (_pData, _cOffset, Numbers.wLeftAfter,   sizeof (WORD));
				AddData (_pData, _cOffset, Numbers.wRightParity, sizeof (BYTE));
				AddData (_pData, _cOffset, Numbers.wRightBefore, sizeof (WORD));
				AddData (_pData, _cOffset, Numbers.wRightAfter,  sizeof (WORD));
				AddData (_pData, _cOffset, Numbers.pCityLeftAfter  ? Numbers.pCityLeftAfter ->cIndex : -1, sizeof (size_t));
				AddData (_pData, _cOffset, Numbers.pCityRightAfter ? Numbers.pCityRightAfter->cIndex : -1, sizeof (size_t));
				AddData (_pData, _cOffset, Numbers.pZipLeftAfter   ? Numbers.pZipLeftAfter  ->cIndex : -1, sizeof (size_t));
				AddData (_pData, _cOffset, Numbers.pZipRightAfter  ? Numbers.pZipRightAfter ->cIndex : -1, sizeof (size_t));
			}
		} else {
			AddData (_pData, _cOffset, 0, sizeof (size_t));
		}
	}
}

static
void _PrepareOrigin (const rgn_origin_t & _origin, size_t & _cBytes) {
	if (_origin.bDeleted)
		return;

	_cBytes += sizeof (BYTE);    // cLevel
	_cBytes += sizeof (point_t); // point
}

static
void _SaveOrigin (const rgn_origin_t & _origin, BYTE * _pData, size_t & _cOffset) {
	AddData (_pData, _cOffset, _origin.cLevel, sizeof (BYTE));
	AddData (_pData, _cOffset, _origin.point,  sizeof (point_t));
}

//////////////////////////////////////////////////////////

void EditCopy () {
	CCritSec::CLock lock (g_cs);

	if (g_Selection.empty ())
		return;

	//
	// Initialize access to the clipboard.
	//

	CClipboard cb;
	::EmptyClipboard ();

	//
	// Estimate the buffer size.
	//
	size_t cBytes = sizeof (size_t);

	const string_t strTypeSet (g_map.pTypeSet->strID);
	cBytes += sizeof (size_t) + strTypeSet.size (); // type set

	cBytes += sizeof (BYTE);    // elevation units
	cBytes += sizeof (WORD);    // wCodePage
	cBytes += sizeof (BYTE);    // cBitsPerSymbol

	// Count levels.
	const size_t cLevels = g_map.Levels.size ();
	cBytes += sizeof (size_t);  // cLevels
	cBytes += sizeof (size_t)*cLevels;
	cBytes += sizeof (size_t)*cLevels;
	cBytes += sizeof (size_t)*cLevels;

	// Prepare postal address items.
	countries_t::iterator ci;
	for (ci = g_map.Countries.begin (); ci != g_map.Countries.end (); ++ ci) {
		country_t & country = * ci;
		country.bMarked = false;
	}
	regions_t::iterator ri;
	for (ri = g_map.Regions.begin (); ri != g_map.Regions.end (); ++ ri) {
		region_t & region = * ri;
		region.bMarked = false;
	}
	cities_t::iterator cti;
	for (cti = g_map.Cities.begin (); cti != g_map.Cities.end (); ++ cti) {
		city_t & city = * cti;
		city.bMarked = false;
	}
	zips_t::iterator zi;
	for (zi = g_map.Zips.begin (); zi != g_map.Zips.end (); ++ zi) {
		zip_t & zip = * zi;
		zip.bMarked = false;
	}

	// Prepare RG nodes.
	g_map.CountRGNodes ();

	rgnodes_t::iterator ni;
	for (ni = g_map.rgnodes.begin (); ni != g_map.rgnodes.end (); ++ ni) {
		rgnode_t & rgnode = * ni;
		rgnode.pExtra = NULL;
	}

	typedef std::map<const rgn_t *, size_t> rgn_idx_map_t;
	rgn_idx_map_t mapIndices;
	size_t cIdx = 0;

	// Count selected items.
	size_t cSelItems = 0;
	cBytes += sizeof (size_t);  // cSelItems
	find_info_m_t::const_iterator i;
	for (i = g_Selection.begin (); i != g_Selection.end (); ++ i) {
		const find_info_t & SelItem = * i;

		if (! SelItem.pLayer || SelItem.iRgn->IsDeleted () || SelItem.iRgn->IsWTR ())
			continue;

		++ cSelItems;

		const rgn_t & rgn = * SelItem.iRgn;
		const bool bIsPolyline = rgn.Kind == rkPolyline;

		mapIndices [& rgn] = cIdx ++;

		// Count size of object's header.
		cBytes += sizeof (USHORT); // ushType
		cBytes += sizeof (BYTE);   // Kind
		cBytes += sizeof (BYTE);   // uchEndLevel
		cBytes += sizeof (BYTE);   // flags
		cBytes += sizeof (size_t) + rgn.strLabel.size ();
		cBytes += sizeof (size_t) + rgn.strComment.size ();
		cBytes += sizeof (size_t) + (rgn.pExtra ? rgn.pExtra->strExtra.size () : 0);
		cBytes += sizeof (size_t); // CityIdx
		cBytes += sizeof (size_t); // ZipIdx
		cBytes += sizeof (size_t) + (rgn.pExtra ? rgn.pExtra->strStreetDesc .size () : 0);
		cBytes += sizeof (size_t) + (rgn.pExtra ? rgn.pExtra->strNumber     .size () : 0);
		cBytes += sizeof (size_t) + (rgn.pExtra ? rgn.pExtra->strPhone      .size () : 0);
		cBytes += sizeof (size_t) + (rgn.pExtra ? rgn.pExtra->strFax        .size () : 0);
		cBytes += sizeof (size_t) + (rgn.pExtra ? rgn.pExtra->strEmail      .size () : 0);
		cBytes += sizeof (size_t) + (rgn.pExtra ? rgn.pExtra->strWebPage    .size () : 0);
		cBytes += sizeof (size_t) + (rgn.pExtra ? rgn.pExtra->strDescription.size () : 0);
		cBytes += sizeof (DWORD);  // dwRouteParams
		cBytes += sizeof (size_t); // cElements or cOrigins

		if (rgn.pExtra && rgn.pExtra->pCity)
			rgn.pExtra->pCity->bMarked = true;
		if (rgn.pExtra && rgn.pExtra->pZip)
			rgn.pExtra->pZip->bMarked = true;

		if (SelItem.cElementOrOrigin == -1) {
			const rgn_elements_t & elements = rgn.elements;
			const size_t cElements = elements.size ();
			if (cElements) {
				// Count size of elements.
				for (size_t cElement = 0; cElement < cElements; ++ cElement) {
					const rgn_element_t & element = elements [cElement];
					_PrepareElement (element, bIsPolyline, cBytes);
				}
			} else {
				// Count size of origins.
				const rgn_origins_t & origins = rgn.origins;
				const size_t cOrigins = origins.size ();
				for (size_t cOrigin = 0; cOrigin < cOrigins; ++ cOrigin) {
					const rgn_origin_t & origin = origins [cOrigin];
					_PrepareOrigin (origin, cBytes);
				}
			}
		} else {
			if (! rgn.elements.empty ()) {
				const rgn_element_t & element = rgn.elements [SelItem.cElementOrOrigin];
				_PrepareElement (element, bIsPolyline, cBytes);
			} else {
				const rgn_origin_t & origin   = rgn.origins  [SelItem.cElementOrOrigin];
				_PrepareOrigin (origin, cBytes);
			}
		}
	}

	// Count cities.
	size_t cIndex = 0;
	for (cti = g_map.Cities.begin (); cti != g_map.Cities.end (); ++ cti) {
		city_t & city = * cti;
		if (city.IsDeleted () || city.bMarked == false)
			continue;

		city.cIndex = cIndex ++;
		city.pRegion->bMarked = true;

		cBytes += sizeof (size_t) + city.strName.size ();
		cBytes += sizeof (size_t);
	}
	const size_t cCities = cIndex;
	cBytes += sizeof (size_t);

	// Count regions.
	cIndex = 0;
	for (ri = g_map.Regions.begin (); ri != g_map.Regions.end (); ++ ri) {
		region_t & region = * ri;
		if (region.IsDeleted () || region.bMarked == false)
			continue;

		region.cIndex = cIndex ++;
		region.pCountry->bMarked = true;

		cBytes += sizeof (size_t) + region.strName.size ();
		cBytes += sizeof (size_t) + region.strAbbrevName.size ();
		cBytes += sizeof (size_t);
	}
	const size_t cRegions = cIndex;
	cBytes += sizeof (size_t);

	// Count countries.
	cIndex = 0;
	for (ci = g_map.Countries.begin (); ci != g_map.Countries.end (); ++ ci) {
		country_t & country = * ci;
		if (country.IsDeleted () || country.bMarked == false)
			continue;

		country.cIndex = cIndex ++;

		cBytes += sizeof (size_t) + country.strName.size ();
		cBytes += sizeof (size_t) + country.strAbbrevName.size ();
	}
	const size_t cCountries = cIndex;
	cBytes += sizeof (size_t);

	// Count zip codes.
	cIndex = 0;
	for (zi = g_map.Zips.begin (); zi != g_map.Zips.end (); ++ zi) {
		zip_t & zip = * zi;
		if (zip.IsDeleted () || zip.bMarked == false)
			continue;

		zip.cIndex = cIndex ++;

		cBytes += sizeof (size_t) + zip.strName.size ();
	}
	const size_t cZips = cIndex;
	cBytes += sizeof (size_t);

	// Count RG nodes.
	cIndex = 0;
	for (ni = g_map.rgnodes.begin (); ni != g_map.rgnodes.end (); ++ ni) {
		rgnode_t & rgnode = * ni;
		if (! rgnode.IsUsed () || rgnode.pExtra == NULL)
			continue;

		rgnode.pExtra = reinterpret_cast<void *> (++ cIndex);
		cBytes += sizeof (size_t); // NodeID
		cBytes += sizeof (BYTE);   // bIsExternal
	}
	const size_t cRGNodes = cIndex;
	cBytes += sizeof (size_t);

	size_t cRestrictions = 0;
	rgrestrictions_t::iterator iRestriction;
	for (iRestriction = g_map.rgrestrictions.begin (); iRestriction != g_map.rgrestrictions.end (); ++ iRestriction) {
		const rgrestriction_t & restriction = iRestriction->second;
		if (! restriction.IsValid ())
			continue;

		const rgn_idx_map_t::const_iterator iFromIdx = mapIndices.find (restriction.pFromRoad);
		if (iFromIdx == mapIndices.end ())
			continue;

		const rgn_idx_map_t::const_iterator iToIdx = mapIndices.find (restriction.pToRoad);
		if (iToIdx == mapIndices.end ())
			continue;

		cBytes += sizeof (DWORD);  // NodeID
		cBytes += sizeof (size_t); // from road
		cBytes += sizeof (size_t); // to road
		cBytes += sizeof (BYTE);   // from direction
		cBytes += sizeof (BYTE);   // to direction

		++ cRestrictions;
	}

	cBytes += sizeof (size_t); // cRestrictions

	//
	// Prepare the buffer for data.
	//
	const HGLOBAL hGlobal = ::GlobalAlloc (GMEM_MOVEABLE, cBytes);
	BYTE * const pData = reinterpret_cast<BYTE *> (::GlobalLock (hGlobal));
	if (! pData) {
		::ErrorMsgBox ("Not enough memory to copy.");
		return;
	}

	//
	// Fill the buffer out.
	//
	size_t cOffset = 0;
	AddData (pData, cOffset, cBytes, sizeof (size_t));

	// Save datum & units.
	AddData (pData, cOffset, strTypeSet);
	AddData (pData, cOffset, g_map.Header.ElevationUnits, sizeof (BYTE));
	AddData (pData, cOffset, g_map.Header.wCodePage,      sizeof (WORD));
	AddData (pData, cOffset, g_map.Header.CodeSchema,     sizeof (BYTE));

	// Save levels vector.
	AddData (pData, cOffset, cLevels, sizeof (size_t));
	for (size_t cLevel = 0; cLevel < cLevels; ++ cLevel) {
		const map_level_t & level = g_map.Levels [cLevel];
		AddData (pData, cOffset, level.btBits,        sizeof (size_t));
		AddData (pData, cOffset, level.btBitsRangeTo, sizeof (size_t));
		AddData (pData, cOffset, level.cZoom,         sizeof (size_t));
	}

	// Save countries.
	AddData (pData, cOffset, cCountries, sizeof (size_t));
	for (ci = g_map.Countries.begin (); ci != g_map.Countries.end (); ++ ci) {
		const country_t & country = * ci;
		if (country.IsDeleted () || country.bMarked == false)
			continue;

		AddData (pData, cOffset, country.strName);
		AddData (pData, cOffset, country.strAbbrevName);
	}

	// Save regions.
	AddData (pData, cOffset, cRegions, sizeof (size_t));
	for (ri = g_map.Regions.begin (); ri != g_map.Regions.end (); ++ ri) {
		const region_t & region = * ri;
		if (region.IsDeleted () || region.bMarked == false)
			continue;

		AddData (pData, cOffset, region.strName);
		AddData (pData, cOffset, region.strAbbrevName);
		AddData (pData, cOffset, region.pCountry->cIndex, sizeof (size_t));
	}

	// Save cities.
	AddData (pData, cOffset, cCities, sizeof (size_t));
	for (cti = g_map.Cities.begin (); cti != g_map.Cities.end (); ++ cti) {
		const city_t & city = * cti;
		if (city.IsDeleted () || city.bMarked == false)
			continue;

		AddData (pData, cOffset, city.strName);
		AddData (pData, cOffset, city.pRegion->cIndex, sizeof (size_t));
	}

	// Save zips.
	AddData (pData, cOffset, cZips, sizeof (size_t));
	for (zi = g_map.Zips.begin (); zi != g_map.Zips.end (); ++ zi) {
		const zip_t & zip = * zi;
		if (zip.IsDeleted () || zip.bMarked == false)
			continue;

		AddData (pData, cOffset, zip.strName);
	}

	// Save RG nodes.
	AddData (pData, cOffset, cRGNodes, sizeof (size_t));
	for (ni = g_map.rgnodes.begin (); ni != g_map.rgnodes.end (); ++ ni) {
		rgnode_t & rgnode = * ni;
		if (! rgnode.IsUsed () || rgnode.pExtra == NULL)
			continue;

		AddData (pData, cOffset, rgnode.dwNodeID,    sizeof (DWORD));
		AddData (pData, cOffset, rgnode.bIsExternal, sizeof (BYTE));
	}

	// Save selected items.
	AddData (pData, cOffset, cSelItems, sizeof (size_t));
	for (i = g_Selection.begin (); i != g_Selection.end (); ++ i) {
		const find_info_t & SelItem = * i;

		if (! SelItem.pLayer || SelItem.iRgn->IsDeleted () || SelItem.iRgn->IsWTR ())
			continue;

		const rgn_t & rgn = * SelItem.iRgn;
		const bool bIsPolyline = rgn.Kind == rkPolyline;

		// Save the objects's header.
		AddData (pData, cOffset, rgn.GetType (),  sizeof (USHORT));
		AddData (pData, cOffset, rgn.Kind,        sizeof (BYTE));
		AddData (pData, cOffset, rgn.uchEndLevel, sizeof (BYTE));
		AddData (pData, cOffset, rgn.dwFlags,     sizeof (BYTE));
		AddData (pData, cOffset, rgn.strLabel);
		AddData (pData, cOffset, rgn.strComment);
		AddData (pData, cOffset, rgn.pExtra ? rgn.pExtra->strExtra : "");

		AddData (pData, cOffset, rgn.pExtra && rgn.pExtra->pCity ? rgn.pExtra->pCity->cIndex : -1, sizeof (size_t));
		AddData (pData, cOffset, rgn.pExtra && rgn.pExtra->pZip  ? rgn.pExtra->pZip->cIndex  : -1, sizeof (size_t));
		AddData (pData, cOffset, rgn.pExtra ? rgn.pExtra->strStreetDesc  : "");
		AddData (pData, cOffset, rgn.pExtra ? rgn.pExtra->strNumber      : "");
		AddData (pData, cOffset, rgn.pExtra ? rgn.pExtra->strPhone       : "");
		AddData (pData, cOffset, rgn.pExtra ? rgn.pExtra->strFax         : "");
		AddData (pData, cOffset, rgn.pExtra ? rgn.pExtra->strEmail       : "");
		AddData (pData, cOffset, rgn.pExtra ? rgn.pExtra->strWebPage     : "");
		AddData (pData, cOffset, rgn.pExtra ? rgn.pExtra->strDescription : "");
		AddData (pData, cOffset, rgn.pExtra ? rgn.pExtra->dwRouteParams  : 0, sizeof (DWORD));

		if (SelItem.cElementOrOrigin == -1) {
			const rgn_elements_t & elements = rgn.elements;
			const size_t cElements = elements.size ();
			if (cElements) {
				// Count elements.
				size_t cSavedElements = rgn.GetElements ();
				AddData (pData, cOffset, cSavedElements, sizeof (size_t));

				// Save elements.
				for (size_t cElement = 0; cElement < cElements; ++ cElement) {
					const rgn_element_t & element = elements [cElement];
					if (element.bDeleted)
						continue;

					_SaveElement (element, bIsPolyline, pData, cOffset);
				}
			} else {
				const rgn_origins_t & origins = rgn.origins;
				const size_t cOrigins = origins.size ();

				// Count origins.
				size_t cSavedOrigins = rgn.GetOrigins ();
				AddData (pData, cOffset, cSavedOrigins, sizeof (size_t));

				// Save origins.
				for (size_t cOrigin = 0; cOrigin < cOrigins; ++ cOrigin) {
					const rgn_origin_t & origin = origins [cOrigin];
					if (origin.bDeleted)
						continue;

					_SaveOrigin (origin, pData, cOffset);
				}
			}
		} else {
			if (! rgn.elements.empty ()) {
				const rgn_element_t & element = rgn.elements [SelItem.cElementOrOrigin];
				if (! element.bDeleted) {
					AddData (pData, cOffset, 1, sizeof (size_t));

					_SaveElement (element, bIsPolyline, pData, cOffset);
				} else
					AddData (pData, cOffset, 0, sizeof (size_t));
			} else {
				const rgn_origin_t & origin = rgn.origins [SelItem.cElementOrOrigin];
				if (! origin.bDeleted) {
					AddData (pData, cOffset, 1, sizeof (size_t));

					_SaveOrigin (origin, pData, cOffset);
				} else
					AddData (pData, cOffset, 0, sizeof (size_t));
			}
		}
	}

	// Save turn restrictions.
	AddData (pData, cOffset, cRestrictions, sizeof (size_t));
	for (iRestriction = g_map.rgrestrictions.begin (); iRestriction != g_map.rgrestrictions.end (); ++ iRestriction) {
		const rgrestriction_t & restriction = iRestriction->second;
		if (! restriction.IsValid ())
			continue;

		const rgn_idx_map_t::const_iterator iFromIdx = mapIndices.find (restriction.pFromRoad);
		if (iFromIdx == mapIndices.end ())
			continue;

		const rgn_idx_map_t::const_iterator iToIdx = mapIndices.find (restriction.pToRoad);
		if (iToIdx == mapIndices.end ())
			continue;

		AddData (pData, cOffset, reinterpret_cast<DWORD> (restriction.pNode->pExtra) - 1, sizeof (DWORD));
		AddData (pData, cOffset, iFromIdx->second,                               sizeof (size_t));
		AddData (pData, cOffset, iToIdx->second,                                 sizeof (size_t));
		AddData (pData, cOffset, static_cast<BYTE> (restriction.bFromDirection), sizeof (BYTE));
		AddData (pData, cOffset, static_cast<BYTE> (restriction.bToDirection),   sizeof (BYTE));
	}

	assert (cOffset == cBytes);
	::GlobalUnlock (hGlobal);

	//
	// Copy the buffer.
	//
	::SetClipboardData (g_uiClipboardFormat, hGlobal);
}